-- AssistMonsterM
-- Create by panyl Jul/26/2016
-- 辅助类怪物模块

module("AssistMonsterM", package.seeall);

-- 配置表
local assistTable = {};

local whenCallSummon = nil;
local whenSummonDie = nil;
local whenGridDisable = nil;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    assistTable = {};

    -- 转换monster_CSV表
    local monster_assist_CSV = get_monster_assist_CSV();
    for i = 1, #monster_assist_CSV do
        assistTable[monster_assist_CSV[i].id] = monster_assist_CSV[i];
    end
    monster_assist_CSV = {};
end

-- 模块初始化
function init()
    loadCsv();

    EventMgr.removeAll("AssistMonsterM");
    EventMgr.register("AssistMonsterM", event.CALL_SUMMON, whenCallSummon);
    EventMgr.register("AssistMonsterM", event.SUMMON_DIE, whenSummonDie);
    EventMgr.register("AssistMonsterM", event.CHANGE_GRID_STATE, whenGridDisable);
end

function query(id, path)
    local m = assistTable[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

function openGridHandle(para)
    local pos = para.pos;
    local grid = DungeonM.getGridByPos(pos);
    local monster = grid.monster;

    -- 更新下格子的光环数据
    updateGridAssistData();

    if not monster then
        return;
    end

    if #PropM.fetchProps(monster, "assist_prop") <= 0 then
        return;
    end

    -- 更新下光环数据
    updateAssistData();
end

function whenMonsterDie(monster)
    if #PropM.fetchProps(monster, "assist_prop") <= 0 then
        return;
    end

    -- 更新下光环数据
    updateAssistData();
end

whenCallSummon = function(para)
    local summon = para.summon;
    if not summon or #PropM.fetchProps(summon, "assist_prop") <= 0 then
        return;
    end

    updateSummonAssist();
end

whenSummonDie = function(para)
    local summon = para.summon;
    if not summon or #PropM.fetchProps(summon, "assist_prop") <= 0 then
        return;
    end

    updateSummonAssist();
end

-- 格子失效之后
whenGridDisable = function(para)
    if para.state ~= GRID_STATE_DISABLE then
        return;
    end

    local pos = para.pos;
    local grid = DungeonM.getGridByPos(pos);
    if not grid.assist_prop then
        return;
    end

    updateGridAssistData();
end

function fetchAssistProps(id, count)
    assert(count <= 30);

    if count <= 0 then
        return {};
    end

    local data = query(id);

    -- 不可重复的
    if 1 ~= data["repeat"] then
        count = 1;
    end

    local prop = data["prop"];
    local ret = { prop[1], prop[2], 0, prop[4]};
    while count > 0 do
        count = count - 1;

        ret[3] = ret[3] + prop[3];
    end

    return { ret };
end

-- 检查怪物出现
function checkMonsterAppear(pos)
    local grid = DungeonM.getGridByPos(pos);
    local monster = grid.monster;
    if not monster then
        return;
    end

    updateAssistData();
    updateGridAssistData();
    updateSummonAssist();
end

function getAssistProps(target)
    local assist_data = target.dbase:queryTemp("assist_data", {});
    local props = {};
    for _, prop in pairs(assist_data) do
        table.insert(props, prop);
    end

    return props;
end

function updateAssistData()
    if not DungeonM.isInDungeon() then
        return;
    end

    local targetMap = { };
    local allMonsters = {};
    local assistList = {};

    -- 先删除旧的光环附加属性
    if #ME.user.dbase:queryTemp("prop", "assist", {}) > 0 then
        PropM.deleteProp(ME.user, "assist");
    end
    ME.user.dbase:setTemp("assist_map", {});

    -- 先遍历一遍过滤出所有的光环怪
    for pos = 1, GRID_SIZE do
        repeat
            local grid = DungeonM.getGridByPos(pos);
            local monster = grid.monster;

            if not monster then
                break;
            end

            -- 如果怪物已经死亡了
            if monster:isDead() then
                break;
            end

            -- 先删除旧的光环附加属性
            if #monster.dbase:queryTemp("prop", "assist", {}) > 0 then
                PropM.deleteProp(monster, "assist");
            end

            monster.dbase:setTemp("assist_map", {});

            -- 先把怪物缓存
            table.insert(allMonsters, monster);

            -- 按照base_id缓存
            local baseId = tostring(monster:query("base_class_id"));
            targetMap[baseId] = targetMap[baseId] or {};

            table.insert(targetMap[baseId], monster);

            -- 如果格子已经翻开，且有光环
            if grid:isOpened() and #PropM.fetchProps(monster, "assist_prop") > 0 then
                table.insert(assistList, monster);
            end

        until true;
    end

    -- 遍历光环怪物
    for _, monster in pairs(assistList) do
        local props = getAssistProps(monster);-- PropM.fetchProps(monster, "assist_prop");

        for _, prop in pairs(props) do
            local assistId = prop[3];
            local targetId = prop[2];
            local targets = {};

            -- 如果是对玩家的
            if "user" == targetId then
                targets = { ME.user, };
            elseif "*" == targetId then
                -- 群体的
                for _, target in pairs(allMonsters) do
                    repeat
                        -- 不能对自己
                        if target == monster then
                            break;
                        end

                        -- 同类不能加成
                        if 1 ~= query(assistId, "indifference") and
                            target:query("base_class_id") == monster:query("base_class_id") then
                            break;
                        end

                        table.insert(targets, target);
                    until true;
                end
            elseif "self" == targetId then
                -- 针对自己
                targets = { monster, };
            else
                -- 针对个别目标(去掉自己)
                targets = table.copy(targetMap[targetId] or {});
                table.removeItem(targets, monster);
            end

            -- 统计
            for _, target in pairs(targets) do
                local assistMap = target.dbase:queryTemp("assist_map");
                assistMap[assistId] = (assistMap[assistId] or 0) + 1;
            end
        end
    end

    -- 把光环属性刷到身上
    table.insert(allMonsters, ME.user);
    for _, target in pairs(allMonsters) do
        local data = target.dbase:queryTemp("assist_map");

        if sizeof(data) > 0 then
            -- 收集属性
            local assistProps = {};
            for assistId, count in pairs(data) do
                assistProps = table.append(assistProps, fetchAssistProps(assistId, count));
            end

            -- 记录属性
            PropM.multiRecord(target, assistProps, "assist");
        end
    end
end

-- 更新下格子的光环数据
function updateGridAssistData()
    if not DungeonM.isInDungeon() then
        return;
    end

    local targetMap = { };
    local allMonsters = {};
    local assistList = {};

    -- 先删除旧的光环附加属性
    if #ME.user.dbase:queryTemp("prop", "assist_grid", {}) > 0 then
        PropM.deleteProp(ME.user, "assist_grid");
    end
    ME.user.dbase:setTemp("assist_grid_map", {});

    -- 先遍历一遍过滤出所有的光环怪
    for pos = 1, GRID_SIZE do
        repeat
            local grid = DungeonM.getGridByPos(pos);
            local monster = grid.monster;

            -- 如果格子已经翻开，且有光环
            if grid:isOpened() and grid.state ~= GRID_STATE_DISABLE then
                if grid.assist_prop then
                    table.insert(assistList, grid);
                end
            end

            if not monster then
                break;
            end

            -- 如果怪物已经死亡了
            if monster:isDead() then
                break;
            end

            -- 先删除旧的光环附加属性
            if #monster.dbase:queryTemp("prop", "assist_grid", {}) > 0 then
                PropM.deleteProp(monster, "assist_grid");
            end

            monster.dbase:setTemp("assist_grid_map", {});

            -- 先把怪物缓存
            table.insert(allMonsters, monster);

            -- 按照base_id缓存
            local baseId = tostring(monster:query("base_class_id"));
            targetMap[baseId] = targetMap[baseId] or {};

            table.insert(targetMap[baseId], monster);
        until true;
    end

    -- 遍历光环格子
    for _, grid in pairs(assistList) do
        local props = grid.assist_prop;

        for _, prop in pairs(props) do
            local assistId = prop[3];
            local targetId = prop[2];
            local targets = {};
            local monster = grid.monster;

            -- 如果是对玩家的
            if "user" == targetId then
                targets = { ME.user, };
            elseif "*" == targetId then
                -- 群体的
                for _, target in pairs(allMonsters) do
                    repeat
                        -- 不能对自己
                        if target == monster then
                            break;
                        end

                        -- 同类不能加成
                        if 1 ~= query(assistId, "indifference") and monster and
                            target:query("base_class_id") == monster:query("base_class_id") then
                            break;
                        end

                        table.insert(targets, target);
                    until true;
                end
            elseif "self" == targetId then
                -- 针对自己
                targets = { monster, };
            else
                -- 针对个别目标(去掉自己)
                targets = table.copy(targetMap[targetId] or {});
                table.removeItem(targets, monster);
            end

            -- 统计
            for _, target in pairs(targets) do
                local assistMap = target.dbase:queryTemp("assist_grid_map");
                assistMap[assistId] = (assistMap[assistId] or 0) + 1;
            end
        end
    end

    -- 把光环属性刷到身上
    table.insert(allMonsters, ME.user);
    for _, target in pairs(allMonsters) do
        local data = target.dbase:queryTemp("assist_grid_map");

        if sizeof(data) > 0 then
            -- 收集属性
            local assistProps = {};
            for assistId, count in pairs(data) do
                assistProps = table.append(assistProps, fetchAssistProps(assistId, count));
            end

            -- 记录属性
            PropM.multiRecord(target, assistProps, "assist_grid");
        end
    end
end

-- 召唤兽的光环
function updateSummonAssist()
    -- 先删除旧的光环附加属性
    if #ME.user.dbase:queryTemp("prop", "assist_summon", {}) > 0 then
        PropM.deleteProp(ME.user, "assist_summon");
    end
    ME.user.dbase:setTemp("assist_summon_map", {});

    -- 先过滤出所有的怪物
    local targetMap = {};
    local allMonsters = {};
    for pos = 1, GRID_SIZE do
        repeat
            local grid = DungeonM.getGridByPos(pos);
            local monster = grid.monster;

            if not monster or monster:isDead() then
                break;
            end

            -- 先删除旧的光环附加属性
            if #monster.dbase:queryTemp("prop", "assist_summon", {}) > 0 then
                PropM.deleteProp(monster, "assist_summon");
            end

            monster.dbase:setTemp("assist_summon_map", {});

            table.insert(allMonsters, monster);

            -- 按照base_id缓存
            local base_id = tostring(monster:query("base_class_id"));
            targetMap[base_id] = targetMap[base_id] or {};

            table.insert(targetMap[base_id], monster);

        until true;
    end

    local assist_map = {};
    local summon_list = ME.user.dbase:queryTemp("summon_list", {});

    for _, summon in pairs(summon_list) do
        repeat
            if not summon then
                break;
            end

            -- 如果召唤兽死亡了
            if summon:isDead() then
                break;
            end

            local props = getAssistProps(summon);   -- PropM.fetchProps(summon, "assist_prop");

            for _, prop in pairs(props) do
                local assistId = prop[3];
                local targetId = prop[2];
                local targets = {};

                -- 如果是对玩家的
                if "user" == targetId then
                    targets = { ME.user, };
                elseif "*" == targetId then
                    -- 群体的
                    targets = allMonsters;
                else
                    -- 针对个别目标(去掉自己)
                    targets = table.copy(targetMap[targetId] or {});
                    table.removeItem(targets, summon);
                end

                -- 统计
                for _, target in pairs(targets) do
                    local assistMap = target.dbase:queryTemp("assist_summon_map");
                    assistMap[assistId] = (assistMap[assistId] or 0) + 1;
                end
            end
        until true;
    end

    -- 把光环属性刷到身上
    table.insert(allMonsters, ME.user);
    for _, target in pairs(allMonsters) do
        local data = target.dbase:queryTemp("assist_summon_map");

        if sizeof(data) > 0 then
            -- 收集属性
            local assistProps = {};
            for assistId, count in pairs(data) do
                assistProps = table.append(assistProps, fetchAssistProps(assistId, count));
            end

            -- 记录属性
            PropM.multiRecord(target, assistProps, "assist_summon");
        end

        if OBJECT_TYPE_USER == target.type then
            EventMgr.fire(event.USER_INFO_UPDATED);
        end
    end
end

-- 获取光环描述
function getAssistDesc(id, count)
    local prop = fetchAssistProps(id, count)[1];
    if not prop then
        return "";
    end

    local dbase = query(id, "dbase") or {};
    if dbase["desc"] and dbase["desc"] == "skill_desc"
        and type(prop) == "table" then
        -- 使用技能的
        return SkillM.getSkillDesc(prop[3]);
    end

    -- 没有配置，直接用prop的描述
    local desc  = query(id, "desc");
    if not desc or #desc == 0 then
        return PropM.getPropDesc(prop);
    end

    -- 如果是百分比
    local v = prop[3];
    if PropM.getRow(prop[1])["type"] == PROP_TYPE_RATIO then
        v = v / 10;
    end

    desc = string.gsub(desc, "{prop}", v);

    return desc;
end
